import numpy as np
import time
import os
import pickle
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, AdaBoostClassifier, StackingClassifier, VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import BaggingClassifier
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.pipeline import Pipeline
from sklearn.utils import shuffle
from tqdm import tqdm
from PIL import Image
from imutils import paths

# 设置随机种子
np.random.seed(42)

# 定义函数读取数据
def load_data(train_folder):
    image_paths = list(paths.list_images(train_folder))
    data = []
    labels = []
    for image_path in tqdm(image_paths, desc="读取图像"):
        image = Image.open(image_path)
        image = image.resize((32, 32))
        image_array = np.array(image).flatten()
        data.append(image_array)
        label = image_path.split(os.path.sep)[-1].split('.')[0]
        labels.append(1 if label == 'dog' else 0)
    return np.array(data), np.array(labels)

# 定义函数保存模型
def save_model(model, model_name):
    with open(model_name, 'wb') as f:
        pickle.dump(model, f)

# 定义函数训练模型
def train_model(X_train, y_train, model):
    model.fit(X_train, y_train)
    return model

# 定义函数评估模型
def evaluate_model(model, X_test, y_test):
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    return accuracy

# 加载数据
train_folder = "C:/Users/86178/Desktop/faiss_dog_cat_question-main/cat_dog_data/data/train"
X, y = load_data(train_folder)

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

# 特征缩放
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

# 训练集成学习模型
models = []
models.append(('logistic_regression', LogisticRegression()))
models.append(('random_forest', RandomForestClassifier()))
models.append(('svm', SVC(probability=True)))
models.append(('hard_voting', VotingClassifier(estimators=[('rf', RandomForestClassifier()), ('svc', SVC(probability=True))])))
models.append(('soft_voting', VotingClassifier(estimators=[('rf', RandomForestClassifier()), ('svc', SVC(probability=True))], voting='soft')))
models.append(('bagging', BaggingClassifier()))
models.append(('stacking', StackingClassifier(estimators=[('rf', RandomForestClassifier()), ('svc', SVC(probability=True))])))
models.append(('adaboost', AdaBoostClassifier()))
models.append(('gradient_boosting', GradientBoostingClassifier()))
models.append(('stacking', StackingClassifier(estimators=[('rf', RandomForestClassifier()), ('svc', SVC(probability=True))])))

best_accuracy = 0
best_model = None
best_model_name = None

# 训练并评估每个模型
for name, model in tqdm(models, desc="训练集成学习模型"):
    start_time = time.time()
    trained_model = train_model(X_train, y_train, model)
    accuracy = evaluate_model(trained_model, X_test, y_test)
    elapsed_time = time.time() - start_time
    print(f"{name}模型训练完成。用时{elapsed_time:.4f}秒。准确率: {accuracy:.4f}")
    
    if accuracy > best_accuracy:
        best_accuracy = accuracy
        best_model = trained_model
        best_model_name = name

# 保存最佳模型
save_model(best_model, f"{best_model_name}.pkl")
print(f"{best_model_name}模型保存成功。")

# 输出结果
print(f"最佳模型: {best_model_name}，训练时间: {elapsed_time:.4f}秒，准确率: {best_accuracy:.4f}")